package com.kayt.cyberBar.cuser.business.Util;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.util.Base64;

/**
 * 加密计算的类。目前有md5,sha,des,wgs的加密算法。 wgs为webgame所用的加密算法。
 * 
 * @author Administrator
 * 
 */
public class EncryUtil {
	static Log log = LogFactory.getLog(EncryUtil.class);
	/**
	 * 字节码到16进制的转换
	 * */
	public static String getHexString(byte[] b) {
		if (b == null)
			return null;
		StringBuffer hs = new StringBuffer();
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0XFF);
			if (stmp.length() == 1)
				hs.append("0" + stmp);
			else
				hs.append(stmp);
		}
		return hs.toString();
	}

	/**
	 * 将表示16进制值的字符串转换为byte数组， 和public static String byteArr2HexStr(byte[] arrB)
	 * 互为可逆的转换过程
	 * 
	 * @param strIn
	 *            需要转换的字符串
	 * @return 转换后的byte数组
	 * @throws Exception
	 *             本方法不处理任何异常，所有异常全部抛出
	 * @author abc
	 */
	public static byte[] hexToBytes(String strIn) {
		byte[] arrB = strIn.getBytes();
		int iLen = arrB.length;

		// 两个字符表示一个字节，所以字节数组长度是字符串长度除以2
		byte[] arrOut = new byte[iLen / 2];
		for (int i = 0; i < iLen; i = i + 2) {
			String strTmp = new String(arrB, i, 2);
			arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
		}
		return arrOut;
	}

	/**
	 * md5加密运算
	 * 
	 * @param str
	 *            - 等待加密的字符串
	 * @return 加密后的16进制字符串摘要
	 * */
	public static String toMD5(String str) {
		return toMD5(str.getBytes());
	}

	/**
	 * md5加密运算
	 * 
	 * @param src
	 *            - 等待加密的字符串字节码
	 * @return 加密后的16进制字符串摘要
	 * */
	public static String toMD5(byte[] src) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("md5");
			md5.reset();
			md5.update(src);
			return getHexString(md5.digest());
		} catch (Exception e) {
			log.error("",e);
			return null;
		}
	}

	/**
	 * md5加密运算
	 * 
	 * @param str
	 *            - 等待加密的字符串
	 * @param encode
	 *            - 需要加密的字符串的编码格式
	 * @return 加密后的16进制字符串摘要
	 * */
	public static String toMD5(String str, String encode) {
		byte[] src;
		try {
			src = str.getBytes(encode);
		} catch (UnsupportedEncodingException e) {
			log.error("",e);
			return null;
		}
		return toMD5(src);
	}

	/**
	 * md5加密运算
	 * 
	 * @param in
	 *            - 等待加密的字节码流
	 * @return 加密后的16进制字符串摘要
	 * */
	public static String toMD5(InputStream in) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("md5");
			// 128k
			byte[] bf = new byte[1024 * 128];
			int b = 0;
			while (true) {
				b = in.read(bf);
				if (b < 0)
					break;
				md5.update(bf, 0, b);
			}
			return getHexString(md5.digest());
		} catch (Exception e) {
			log.error("",e);
			return null;
		}
	}

	/**
	 * sha加密运算
	 * 
	 * @param src
	 *            - 等待加密的字符串字节码
	 * @return 加密后的16进制字符串摘要
	 * */
	public static String toSHA(String str) {
		try {
			MessageDigest sha1 = MessageDigest.getInstance("sha");
			sha1.reset();
			sha1.update(str.getBytes());
			return getHexString(sha1.digest());
		} catch (Exception e) {
			log.error("",e);
			return null;
		}
	}

	// des加密
	public static String toDES(byte[] plainText, byte[] desKey1) {
		try {
			Cipher cipher = Cipher.getInstance("DES");

			KeyGenerator kg = KeyGenerator.getInstance("DES");
			kg.init(new SecureRandom(desKey1));
			SecretKey secretKey = kg.generateKey();

			cipher.init(Cipher.ENCRYPT_MODE, secretKey);

			return getHexString(cipher.doFinal(plainText));

		} catch (Exception exp) {
			log.error("",exp);
			return null;
		}
	}

	public static String encryptDes(String text, String key) {
		try {
			String a = encryptDes(text, key, null);
			return a;
		} catch (UnsupportedEncodingException e) {
			log.error("",e);
			return "";
		}
	}

	public static String encryptDes(String text, String key, String encode)
			throws UnsupportedEncodingException {
		byte[] bTxt = null;
		if (encode != null)
			bTxt = text.getBytes(encode);
		else
			bTxt = text.getBytes();
		return toDES(bTxt, key.getBytes());
	}

	public static String decryptDes(String txt, String key, String encode) {
		try {
			Cipher cipher = Cipher.getInstance("DES");

			KeyGenerator kg = KeyGenerator.getInstance("DES");
			kg.init(new SecureRandom(key.getBytes()));
			SecretKey secretKey = kg.generateKey();

			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
			// Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, secretKey);
			byte[] data = hexToBytes(txt);
			if (encode != null)
				return new String(cipher.doFinal(data), encode);
			else
				return new String(cipher.doFinal(data));
		} catch (Exception e) {
			log.error("",e);
			return "";
		}
	}

	/**
	 * 加密算法
	 * 
	 * @param txt
	 *            -String, 待加密文本
	 * @param key
	 *            -String,私匙
	 * @return a String,返回一个base64编码后的摘要base
	 * */
	public static String encryptWGS(String txt, String key) {
		String encryptKey = toMD5(String.valueOf(NumberUtil.getRandom(32000)));
		int ctr = 0;
		String tmp = "";
		for (int i = 0; i < txt.length(); i++) {
			ctr = ctr == encryptKey.length() ? 0 : ctr;
			tmp = tmp + encryptKey.charAt(ctr);
			tmp = tmp + (char) (txt.charAt(i) ^ encryptKey.charAt(ctr++));
		}
		return new String(Base64.encodeBase64(passportKey(tmp, key).getBytes()));
	}

	/**
	 * Passport key
	 * 
	 * @param txt
	 *            -string,
	 * @param key
	 *            -string,
	 * @return a string
	 */
	private static String passportKey(String txt, String encryptKey) {

		encryptKey = toMD5(encryptKey);
		int ctr = 0;
		String tmp = "";

		for (int i = 0; i < txt.length(); i++) {
			ctr = ctr == encryptKey.length() ? 0 : ctr;
			tmp = tmp + (char) (txt.charAt(i) ^ encryptKey.charAt(ctr++));
		}
		return tmp;
	}

	/**
	 * 解密方法
	 * 
	 * @param txt
	 *            -String,base64编码的摘要字符串
	 * @param key
	 *            -String,私匙
	 * @return a String,
	 */
	public static String decryptWGS(String txt, String key) {
		txt = passportKey(new String(Base64.decodeBase64(txt.getBytes())), key);
		String tmp = "";
		for (int i = 0; i < txt.length(); i++) {
			tmp = tmp + (char) (txt.charAt(i) ^ txt.charAt(++i));
		}
		return tmp;
	}
}
